package cn.mybatishelper.common;

import cn.mybatishelper.entity.database.ColumnEntity;
import cn.mybatishelper.entity.vo.TableToMybatisVo;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.*;

/**
 * jdbc工具类
 *
 * @author GameKing
 */
public abstract class JdbcUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(JdbcUtil.class);
    /**
     * 默认分隔符
     */
    public static final String DEFAULT_SEPARATOR = "_";

    /**
     * 关闭数据库连接
     */
    public static void releaseSqlConnection(Connection connection) {
        if (connection == null) {
            return;
        }
        try {
            connection.close();
        } catch (SQLException e) {
            LOGGER.error("关闭数据库连接发生异常", e);
        }
    }

    /**
     * 验证数据库连接和用户名，密码是否可用
     *
     * @param addressUrl
     * @param userName
     * @param password
     * @return
     */
    public static boolean validateDatabase(String addressUrl, String userName, String password) {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(addressUrl, userName, password);
            return connection != null;
        } catch (Exception e) {
            LOGGER.error("验证数据库链接出错", e);
            return false;
        } finally {
            releaseSqlConnection(connection);
        }
    }

    /**
     * 从数据库中获取所有的表名和视图名
     */
    public static String[] getTables(String addressUrl, String userName, String password, String schema) {
        List<String> tables = new ArrayList<String>();
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(addressUrl, userName, password);
            DatabaseMetaData metaData = connection.getMetaData();
            ResultSet resultSet = metaData.getTables(connection.getCatalog(), schema, null, new String[]{"TABLE", "VIEW"});

            while (resultSet.next()) {
                tables.add(resultSet.getString("TABLE_NAME"));
            }
        } catch (Exception e) {
            LOGGER.error("获取所有的表名和视图名出错", e);
        } finally {
            releaseSqlConnection(connection);
        }
        return tables.toArray(new String[tables.size()]);
    }

    /**
     * 根据传入的数据库表结构实体，生成对应的列属性实体
     */
    public static List<ColumnEntity> getColumnEntity(ResultSet resultSet, ResultSet primarySet) {
        if (resultSet == null) {
            return Collections.emptyList();
        }
        List<ColumnEntity> columnList = new ArrayList<ColumnEntity>();
        try {
            Set<String> priSet = new HashSet<String>();
            while (primarySet.next()) {
                priSet.add(primarySet.getString("COLUMN_NAME"));
            }
            while (resultSet.next()) {
                ColumnEntity column = new ColumnEntity();
                String columnName = resultSet.getString("COLUMN_NAME");
                column.setColumnName(columnName);
                column.setPropertyName(convertColumnNameToPropertiyName(columnName));
                column.setJavaType(DataTypeConstants.JDBC_JAVA_MATCH_TYPE.get(resultSet.getString("TYPE_NAME").toLowerCase()));
                column.setJdbcType(DataTypeConstants.JAVA_JDBC_MATCH_TYPE.get(column.getJavaType()));
                if (priSet.contains(columnName)) {
                    column.setPrimaryKey(true);
                }
                columnList.add(column);
            }
        } catch (Exception e) {
            LOGGER.error("生成列属性实体时出错...", e);
        }
        return columnList;
    }

    /**
     * 将列名转为java持久化类中的变量名,将“_”作为分隔符
     *
     * @param columnName
     * @return
     */
    public static String convertColumnNameToPropertiyName(String columnName) {
        String[] names = columnName.split(DEFAULT_SEPARATOR);
        StringBuilder str = new StringBuilder(names[0].toLowerCase());
        for (int i = 1; i < names.length; i++) {
            String upStr = names[i].toLowerCase();
            upStr = upStr.replaceFirst(upStr.substring(0, 1), upStr.substring(0, 1).toUpperCase());
            str.append(upStr);
        }
        return str.toString();
    }

    /**
     * 以默认的规则转换数据库表名为持久化类名，默认分隔符：“_”
     *
     * @param tableName
     * @return
     */
    public static String convertTableNameToObjectName(String tableName) {
        String[] names = tableName.split(DEFAULT_SEPARATOR);
        StringBuilder str = new StringBuilder();
        for (String name : names) {
            String upStr = name.toLowerCase();
            upStr = upStr.replaceFirst(upStr.substring(0, 1), upStr.substring(0, 1).toUpperCase());
            str.append(upStr);
        }
        return str.toString();
    }

    /**
     * 根据传入的参数对表名进行处理，并将之转为持久化类名
     *
     * @param tableName
     * @return
     */
    public static String convertTableNameToObjectNameByParams(String tableName, String separator, String removeString) {
        String targetName = tableName;
        if (StringUtils.isNotBlank(removeString)) {
            targetName = targetName.replace(removeString, "");
        }
        String[] names;
        if (StringUtils.isNotBlank(separator)) {
            names = targetName.split(separator);
        } else {
            names = new String[]{targetName};
        }
        StringBuilder str = new StringBuilder();
        for (String name : names) {
            String upStr = name.toLowerCase();
            upStr = upStr.replaceFirst(upStr.substring(0, 1), upStr.substring(0, 1).toUpperCase());
            str.append(upStr);
        }
        return str.toString();
    }

    /**
     * 根据JUIConstants的值生成转换所需VO
     *
     * @return
     */
    public static List<TableToMybatisVo> createTableToMybatisFromBaseConstants() {
        if (StringUtils.isBlank(BaseInfoConstants.tableNames)) {
            LOGGER.error("JUIConstants中的数据库表名为空，生成操作终止");
            return null;
        }
        List<TableToMybatisVo> voList = new ArrayList<TableToMybatisVo>();
        String[] names = BaseInfoConstants.tableNames.split(",");
        for (String name : names) {
            TableToMybatisVo vo = new TableToMybatisVo();
            vo.setTableName(name);
            vo.setJavaEntityPackageUrl(BaseInfoConstants.poPackage);
            vo.setXmlEntityPackageUrl(BaseInfoConstants.mapperPackage);

            String tableNames = convertTableNameToObjectNameByParams(name, BaseInfoConstants.tableNameSeparate, BaseInfoConstants.tableNameRemove);
            vo.setObjectName(tableNames);
            voList.add(vo);
        }
        return voList;
    }
}
